﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Security.Application;
using System.Web;
using System.Xml;
using System.Text.RegularExpressions;
using System.Globalization;
using System.IO; 

namespace ImPM.Application
{
    public sealed class EncodeDecode
    {
        // Methods
        private EncodeDecode()
        {
        }

        public static string CrlfDecode(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return input;
            }
            return input.Replace("\r", "&#x0D;").Replace("\n", "&#x0A;");
        }

        public static string CrlfToHtmlEncode(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return input;
            }
            return input.Replace("&#x000D;&#x000A;", "<BR>");
        }

        public static string  EncodeCharToDecimal(string input, char whatToEncode)
        {
            ImPMException.Assert((((whatToEncode != ',') && (whatToEncode != '_')) && (whatToEncode != '-')) && (whatToEncode != '.'), " EncodeToDecimal does not support encoding the character: {0}", new object[] { whatToEncode });
            if (string.IsNullOrEmpty(input))
            {
                return input;
            }
            return AntiXss.XmlEncode(input);
        }

        public static string  HtmlAttributeEncode(string input)
        {
            return AntiXss.HtmlAttributeEncode(input);
        }

        public static void  HtmlAttributeEncode(string input, TextWriter writer)
        {
            writer.Write(AntiXss.HtmlAttributeEncode(input));
        }

        public static string  HtmlAttributeEncodeForFormatString(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return input;
            }
            return AntiXss.HtmlAttributeEncode(input).Replace("&#123;", "{").Replace("&#125;", "}");
        }

        public static string  HtmlDecode(string input)
        {
            return HttpUtility.HtmlDecode(input);
        }

        public static string  HtmlEncode(string input)
        {
            return AntiXss.HtmlEncode(input);
        }

        public static void  HtmlEncode(string input, TextWriter writer)
        {
            writer.Write(AntiXss.HtmlEncode(input));
        }

        public static string  HtmlEncodeForFormatString(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return input;
            }
            return AntiXss.HtmlEncode(input).Replace("&#123;", "{").Replace("&#125;", "}");
        }

        public static string  JavaScriptEncode(string input)
        {
            if (input == null)
            {
                return "''";
            }
            return AntiXss.JavaScriptEncode(input);
        }

        public static string  JavaScriptEncodeNoQuotes(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return input;
            }
            string str =  JavaScriptEncode(input);
            return str.Substring(1, str.Length - 2);
        }

        public static string  NameValueDecode(string input)
        {
            return  UrlDecode(input);
        }

        public static string  NameValueEncode(string input)
        {
            return  UrlEncode(input);
        }

        public static string  NewLineToHtmlEncode(string input)
        {
            return input.Replace("\n", "<br>");
        }

        public static string  UrlDecode(string input)
        {
            return HttpUtility.UrlDecode(input);
        }

        public static string  UrlEncode(string input)
        {
            return AntiXss.UrlEncode(input);
        }

        public static string  VBScriptEncode(string input)
        {
            return AntiXss.VisualBasicScriptEncode(input);
        }

        public static string  XmlDecode(string xml)
        {
            if ((xml == null) || (xml.Length == 0))
            {
                return string.Empty;
            }
             //Exception.Assert(!xml.StartsWith("<", StringComparison.Ordinal), " XmlDecode should only be used to decode strings, not XML documents.");
            XmlReader reader = XmlReader.Create(new StringReader("<ROOT>" + xml + "</ROOT>"));
            reader.Read();
            return reader.ReadElementContentAsString();
        }

        public static string  XmlEncode(string input)
        {
            if (encodeSurrogates(ref input, EncodingMethod.Xml))
            {
                return input;
            }
            return AntiXss.XmlEncode(input);
        }

        private static bool encodeSurrogates(ref string input, EncodingMethod encoding)
        {
            if (!string.IsNullOrEmpty(input))
            {
                bool flag = false;
                int index = 0;
                while (index < input.Length)
                {
                    if (char.IsSurrogate(input[index]))
                    {
                        flag = true;
                        break;
                    }
                    index++;
                }
                if (flag)
                {
                    int startIndex = 0;
                    StringBuilder builder = new StringBuilder(input.Length);
                    while (index < input.Length)
                    {
                        if (char.IsSurrogate(input[index]))
                        {
                            switch (encoding)
                            {
                                case EncodingMethod.Xml:
                                    builder.Append(AntiXss.XmlEncode(input.Substring(startIndex, index - startIndex)));
                                    builder.Append("&#x");
                                    builder.Append(char.ConvertToUtf32(input, index).ToString("x", CultureInfo.InvariantCulture));
                                    builder.Append(";");
                                    break;

                                case EncodingMethod.Url:
                                    builder.Append(AntiXss.UrlEncode(input.Substring(startIndex, index - startIndex)));
                                    builder.Append("%u");
                                    builder.Append(char.ConvertToUtf32(input, index).ToString("x", CultureInfo.InvariantCulture));
                                    break;
                            }
                            index += 2;
                            startIndex = index;
                            continue;
                        }
                        index++;
                    }
                    switch (encoding)
                    {
                        case EncodingMethod.Xml:
                            builder.Append(AntiXss.XmlEncode(input.Substring(startIndex, index - startIndex)));
                            break;

                        case EncodingMethod.Url:
                            builder.Append(AntiXss.UrlEncode(input.Substring(startIndex, index - startIndex)));
                            break;
                    }
                    input = builder.ToString();
                    return true;
                }
            }
            return false;
        }

        public static string EscapeCurlyBraceForFormat(string input)
        {
            return input.Replace("{", "{{").Replace("}", "}}");
        }

        // Nested Types
        private enum EncodingMethod : uint
        {
            Url = 2,
            Xml = 1
        }
    }
}
